package controlLayer;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import utilLayer.AlreadyExistsException;
import modelLayer.Subject;
import modelLayer.Teacher;
import dbLayer.DBStudent;
import dbLayer.DBSubject;
import dbLayer.DBSubjectIF;
import dbLayer.DBConnection;

/**
 * This class is a control layer class of the MSAS system. It functions as the link between 
 * our database and the interface. This class is limited to working with the Subject class,
 * and whichever other classes subject is associated with. There is no direct connection between
 * this class and our database.
 * 
 * @author Danny M�lgaard, Anna Kelemen, Jakob Korsgaard
 * 		   
 * @version 1.3.1
 * 					1.3.1: 		Added more extensive documentation. Verified that
 * 								information contained in the Design Class Diagram,
 * 								is in accordance with the information contained in this
 * 								class.
 *					1.3.2:		Try&catch and throws Exception added to the constructor in order to catch
 *								a NullPointerException and to avoid the program from crashing
 *								if there is no connection to the database. 
 */
public class SubjectCtr {
	
	private DBSubjectIF dbSubjectIF;
	
	/**
	 * Creates an instance of SubjectCtr. Initializes an instance of DBSubject.
	 * @throws Exception
	 */
	public SubjectCtr() throws Exception {
		try {
			this.dbSubjectIF = new DBSubject();
		}
		catch (Exception e) {
			throw new Exception();
		}
		
	}
	
	/**
	 * Sends information from the interface on to the database layer, more specifically
	 * helping in the insertion of a new row in the database. Begins a transactions upon
	 * calling the dbLayer method, and rolls it back should anything that could result in dataloss,
	 * or unintended data manipulation occur.
	 * 
	 * @param 	name			String		name of the subject
	 * @param 	description		String		subject description
	 * @param	t				Teacher		teacher to be associated with the subject
	 * @return 	rc 				int 		count of rows affected by the query execution in the database	
	 * @throws 					Exception
	 */
	public int createSubject(String name, String description) throws Exception {

		int rc = -1;
		try {
			DBConnection.startTransaction();
			rc = this.dbSubjectIF.insert(name, description);
			DBConnection.commitTransaction();
		}
		catch (SQLException ex) {
			DBConnection.rollbackTransaction();
			throw new AlreadyExistsException(name);
		}
		catch (Exception e) {
			DBConnection.rollbackTransaction();
			System.out.println("DEBUG MESSAGE [SUBJECTCTR]: createSubject(): " + e);
		}
		
		return rc;

	}
	
	/**
	 * Sends information from the interface on to the database layer, more specifically
	 * helping in the search of an existing row in the database.
	 * 
	 * @param 	name				String	name of the subject
	 * @param 	retrieveAssociation	determines if we're to retrieve additional information on the subject
	 * @return
	 * @throws 						Exception
	 */
	public Subject findSubject(String name, boolean retrieveAssociation) throws Exception {
		
		Subject s = null;
		try {
			s = this.dbSubjectIF.find(name, retrieveAssociation);
		}
		catch (Exception e) {
			System.out.println("DEBUG MESSAGE [SUBJECTCTR]: findSubject(): " + e);
		}
		
		return s;

	}

	/**
	 * Sends information from the interface on to the database layer, more specifically
	 * helping in the search of an existing row in the database.
	 * 
	 * @param 	id					int		id of the subject
	 * @param 	retrieveAssociation	boolean	determines if we're to retrieve additional information on the subject
	 * @return
	 */
	 public Subject findById(int id, boolean retrieveAssociation) {
		
		Subject s = null;
		try {
			s = this.dbSubjectIF.findById(id, retrieveAssociation);
		}
		catch (Exception e) {
			System.out.println("DEBUG MESSAGE [SUBJECTCTR]: findById(): " + e);
		}
		
		return s;
		
	}
	
	/**
	 * Sends information from the interface on to the database layer, more specifically
	 * helping in the search of all existing rows in the database.
	 *  
	 * @param 	retrieveAssociation	boolean			determines if we're to retrieve additional information 
	 * 												on the subject
	 * @return 						List<Subject> 	list of subjects
	 * @throws						Exception
	 */	 
	public List<Subject> getAll(boolean retrieveAssociation) throws Exception {
	// public Map<String, Subject> getAll(boolean retrieveAssociation) throws Exception {	
		List<Subject> list = null;
		//Map<String, Subject> subjects = null;
		try {
			list = this.dbSubjectIF.getAll(retrieveAssociation);
//			subjects = new HashMap<String, Subject>();
//			for (Subject s : list){
//				if (!subjects.containsKey(s.getName())){
//					subjects.put(s.getName(), s);
//				}
//			}
		}
		catch (Exception e) {
			System.out.println("DEBUG MESSAGE [SUBJECTCTR]: getAll(): " + e);
		}
		return list;
		//return subjects;
			
	}
	
	/**
	 * Sends information from the interface on to the database layer, more specifically
	 * helping in the renewal of an existing row in the database. Begins a transactions upon
	 * calling the dbLayer method, and rolls it back should anything that could result in data loss,
	 * or unintended data manipulation occur.
	 * 
	 * @param 	s	Subject		instance of the subject which is to be updated
	 * @return	rc	int			count of rows affected by the query execution in the database
	 * @throws 		Exception
	 */
	public int updateSubject(Subject s) throws Exception {
		
		int rc = -1;
		try {
			DBConnection.startTransaction();
			rc = this.dbSubjectIF.update(s.getId(), s.getName(), s.getDescription());
			DBConnection.commitTransaction();
		}
		catch (SQLException ex) {
			DBConnection.rollbackTransaction();
			throw new AlreadyExistsException(s.getName());
		}
		catch (Exception e) {
			System.out.println("DEBUG MESSAGE [SUBJECTCTR]: updateSubject(): " + e);
			DBConnection.rollbackTransaction();
		}
		
		return rc;
		
	}
	
	/**
	 * Sends information from the interface on to the database layer, more specifically
	 * helping in the removal of an existing row in the database. Begins a transactions upon
	 * calling the dbLayer method, and rolls it back should anything that could result in data loss,
	 * or unintended data manipulation occur.
	 * 
	 * @param 	s	Subject		instance of the subject which is to be removed
	 * @return	rc				int		count of rows affected by the query execution in the database
	 * @throws 					Exception
	 */
	public int removeSubject(Subject s) throws Exception {
		
		int rc = -1;
		try {
			DBConnection.startTransaction();
			rc = this.dbSubjectIF.remove(s.getName());
			DBConnection.commitTransaction();
		}
		catch(SQLException ex) {
			DBConnection.rollbackTransaction();
			throw new AlreadyExistsException(s.getName());
		}
		catch (Exception e) {
			System.out.println("DEBUG MESSAGE [SUBJECTCTR]: removeSubject(): " + e);
			DBConnection.rollbackTransaction();
		}
		
		return rc;
		
	}

}
